"""
Fortran module error_handling:September 2016
Error handling and reporting module. Exceptional program
conditions (errors) can be signaled, detected, and handled
or reported to the user accordingly.
**Details**
Although more advanced error tracking and error handling
strategies are possible with this class, we suggest as best-practice
the definition of a few macros as shortcuts to the error handling.
But these macros allow lazy programmers to create and propagate
errors with the least possible effort. These macros are defined as
one liners on top of the corresponding modules:
``#define RAISE_ERROR(MSG)
call signal_error(error, __LINE__, __FILE__, MSG, proc_name); return``
``#define TRACK_ERROR(X)
if(detect_error(X)) call signal_error(X, __LINE__, __FILE__, '');
if(detect_error(X)) return``
"""
[docs]
class error_type():
"""
Runtime error signal
**Class variables**
desc : character(:), allocatable
Optional error description. e.g., context.
loc : character(:), allocatable
Location where the error occured, e.g. (sub)program name.
Subsequent error (causal follow-up error(s) in recursion caused
by this one). Shall be nullified if error has not caused any
subsequent error. Usually of generic SubError_type, but further
specializations are possible.
Note: As long as alloc. recursion not fully available, we use
a pointer queue with proper deep-copy and finalization methods
"""
[docs]
def error_deep_copy_to(self):
"""
fortran-subroutine - Deep copy of an error.
**Arguments**
this : error_type, in
Make a copy of the error `this`
copy : error_type, out
Must be of same or extended class than `this`.
As Error_type is baseclass, this will work for any extended Error
type, but it will not copy any of the error's extended components.
On exit, holds the copy of `this`.
**Details**
Copies recursively error and sub-errors into compatible
type variable. Should be overwritten by extensions!
"""
return
[docs]
def error_get_desc(self):
"""
fortran-function - Get error description string
**Arguments**
this : error_type, in
Obtain the description of the error contained in `this`.
**Result**
desc : character(:)
Set to description. If no description set, returns a notification.
"""
return
[docs]
def error_get_loc(self):
"""
fortran-function -
**Arguments**
this : error_type, in
Return the location of the error contained in `this`.
**Result**
loc : character(:)
Set to location. If no location set, returns a notification.
**Details**
Get error location string.
"""
return
[docs]
def error_get_name(self):
"""
fortran-function - Return the error's identifIer
**Arguments**
this : error_type, in
Get the name of the error contained in `this`.
**Result**
name : character(:)
Set to the class name of the error.
"""
return
[docs]
def error_has_sub(self):
"""
fortran-function - Check if error has subsequent errors
**Arguments**
this : error_type, in
Return boolean flag if `this` has sub errors.
**Result**
has_sub : logical
Set to true, if sub-errors are present. Otherwise false.
"""
return
[docs]
def error_load_signal(self):
"""
fortran-subroutine - Load error into signal handle.
**Arguments**
this : error_type, in
this : loaded onto the signal., in
error : error_type, inout
Signal handle. Replaced by `this` on exit.
Signals allocated on entry will be cleared.
**Details**
Default Error_type clears the signal and copies
itself into it. Extensions may behave differently, e.g.
append (SubError_type)
"""
return
[docs]
class suberror_type(error_type):
"""
Subsequent error signals an unhandled error condition.
"""
[docs]
def suberror_load_signal(self):
"""
fortran-subroutine - Load error into signal handle
**Arguments**
this : SubError_type, in
this : loaded onto the signal., in
error : error_type, inout
Signal handle. If clean on input, replaced by
`this` on exit. Othwerwise, `this` is appended
as last 'sub'-component to the existing error.
"""
return
[docs]
class valueerror_type(error_type):
"""
Error signals that describe various exceptional
program conditions.
"""
[docs]
class memoryerror_type(error_type):
"""
No documentation extracted.
**Class variables**
status_value = 0 : integer
Status value from the allocation call, i.e, the
internal status flag could take value of corrupt
allocation status (/= 0).
"""
[docs]
def memoryerror_print_desc(self):
"""
fortran-subroutine - Print a formatted description to output unit for an memory error.
**Arguments**
this : memoryerror_type, in
Print a description of the error contained in `this`.
unit : integer, optional, in
Unit to print error report. Default to std-error unit.
"""
return
[docs]
class arithmeticerror_type(error_type):
"""
Baseclass for all errors during arithmetic operations.
"""
[docs]
class ioerror_type(error_type):
"""
Baseclass for all I/O transfer errors.
**Class variables**
status_value = 0 : integer
Contains the status value of the iostat call
unit_name : character(:), allocatable
filename, or unit identifier.
"""
[docs]
def ioerror_get_unit_name(self):
"""
fortran-function - Obtain the unit name of the file handle.
\reuslt unit_name
unit_name is character(:)
Unit name of the IO error.
**Arguments**
this : IOError_type, in
Get the unit name associated with the error `this`.
"""
return
[docs]
def ioerror_print_desc(self):
"""
fortran-subroutine - Print a formatted description to output unit for an IO error.
**Arguments**
this : ioerror_type, in
Print a description of the error contained in `this`.
unit : integer, optional, in
Unit to print error report. Default to std-error unit.
"""
return
[docs]
def signal_error_full():
"""
fortran-subroutine - ?? (ft)
Signal an exceptional program condition (error).
**Arguments**
error (optional) : error_type, optional, inout
Error signal handle into which the 'new_error' is
loaded by it's `load_signal` method. If 'error'
is not present, the `no_handle_action` will be
triggered.
line_number : integer, in
Line number of the error, intended to be provided
by preprocessor macro __LINE__
filename : character(*), in
Filename where the error occurs, intended to be
provided by macro __FILE__
new_error : error_type, in
The error to be signaled. The user should provide
it with a description of the context and circumstances
of the exceptional condition that is signaled.
Depending on it's 'load_error' method, it modifies the
error. The `new_error` is usually copied. This allows
to provide the `new_error` in an expression, such as a
derived-type constructor, e.g.
`signal_error(..., ValueError_type("..."))`.
proc_name : character(*), optional, in
name of the affected function/subroutine. This location
will be part of the displayed message in error reports,
and serves as a trace to the part of the code where the
error occured.
no_handle_action : character, optional, in
Can be either 'N' for nothing, 'R' for report and continue,
or 'S' for report and stop. If not provided, the module-wide
ErrorHandling_no_handle_action is used.
**Details**
Indicate that a specified error has occured at a
given location. The error will be loaded on the signal in
an error-specific way (e.g. replace signal, append to
existing errors, etc., see `load_signal`)
"""
return
[docs]
def signal_error_macro():
"""
fortran-subroutine - July 2021 (dj)
Signal an unspecified error allowing on to specify line number
and filename.
**Arguments**
error : error_type, optional, inout
error handling class to track error.
line_number : integer, in
Line number of the error, intended to be provided
by preprocessor macro __LINE__
filename : character(*), in
Filename where the error occurs, intended to be
provided by macro __FILE__
desc : character(*), in
description of the error, i.e., error message.
proc_name : character(*), optional, in
name of the affected function/subroutine. This location
will be part of the displayed message in error reports,
and serves as a trace to the part of the code where the
error occured.
no_handle_action : character, optional, in
Can be either 'N' for nothing, 'R' for report and continue,
or 'S' for report and stop. If not provided, the module-wide
ErrorHandling_no_handle_action is used.
"""
return
[docs]
def stop_on_error():
"""
fortran-subroutine - Stop program on active error.
**Arguments**
error : error_type, allocatable, optional, in
Check if error was set and exit program.
**Details**
Stops with error exit-code and reports error if active.
If signal is clean, nothing is done.
"""
return
[docs]
def detect_error():
"""
fortran-function -
**Arguments**
error : error_type, allocatable, optional, in
Check this error type if currently an error is
present
**Result**
detected : logical
detected : present
and allocated with an error.
**Details**
Check if error is present in signal
"""
return
[docs]
def clear_error():
"""
fortran-subroutine - ?? (ft)
Clear all errors from signal
**Arguments**
error : error_type, allocatable, optional, inout
Reset this error into a clean state.
**Details**
Resets signal-handle into a clean state.
Any signaled errors will become deleted from the handle.
Use after resolving an error, or to signal a higher priority
error instead that would otherwise get appended as sub-error.
"""
return
[docs]
def load_error():
"""
fortran-subroutine - Load error into signal
**Arguments**
error : error_type, allocatable, optional, inout
Loads provided error into signal, if signal-handle
present. See `Error_type%load_signal`
new_error : error_type, in
Combining new error into previous one `error`.
**Details**
The subroutine is useful when dealing
with multiple (local) signal handles
"""
return
[docs]
def report_error():
"""
fortran-subroutine -
**Arguments**
error : error_type, allocatable, optional, in
Error to be reported.
unit : integer, optional, in
Unit to print error report. Default to std-error unit.
**Details**
Print error report to output unit
Prints a formatted report of an active error and all subsequent
errors. Nothing is done if signal-handle is not present or signal is
clean. The report starts with a header, followed by a cronologically
ordered list of error locations and formatted descriptions, starting
with this error, followed by it's subsequent errors.
"""
return
[docs]
def get_error_unit():
"""
fortran-function - ??
**Arguments**
unit : integer, optional., in
If present, the returned error output unit is
set to unit
as module variable `ErrorHandling_error_unit`.
**Result**
err_unit : integer
Either `unit` if present or default unit defined
**Details**
Returns module-wide default error output unit
"""
return
[docs]
def error_append_sub():
"""
fortran-subroutine -
**Arguments**
this : error_type, inout
Append another error as suberror to `this`.
sub : error_type, in
Appends deep copy of `sub` in the list of subsequent
errors of `this`.
**Details**
Append subsequent error.
"""
return
[docs]
def error_final():
"""
fortran-subroutine - Finalization of an error in the sense of deallocating it.
**Arguments**
this : error_type, inout
Deallocate all memory allocated for `this`, i.e.,
Clean up pointer components, here 'sub' errors.
"""
return
[docs]
def error_print_desc():
"""
fortran-subroutine - Print a formatted description to output unit.
**Arguments**
this : error_type, in
Print a description of the error contained in `this`.
unit : integer, optional, in
Unit to print error report. Default to std-error unit.
**Details**
Extensions shall briefly state their specific
information incl. 'desc' The location is printed separately
as a header information.
"""
return
[docs]
def error_print_report():
"""
fortran-subroutine -
**Arguments**
this : error_type, in
Print formatted report of the complete error contained in `this`.
unit : integer, optional, in
Unit to print error report. Default to std-error unit.
**Details**
Print error report to output unit.
Includes a header/preamble with the location, followed by the
description.
Prints the report of subsequent error(s) separated by a blank line.
The report always ends with one blank line.
"""
return
[docs]
def error_create():
"""
fortran-function - Constructor for error instance.
**Arguments**
desc : character(:), in
Description by the user to describe the error.
**Result**
error : error_type
Create an error when given the description `desc`.
"""
return
[docs]
def suberror_create():
"""
fortran-function - Constructor for SubError instance.
**Arguments**
desc : character(:), in
Description by the user to describe the suberror.
**Result**
error : suberror_type
Create a suberror when given the description `desc`.
"""
return
[docs]
def valueerror_create():
"""
fortran-function - Constructor for ValueError instance.
**Arguments**
desc : character(:), in
Description by the user to describe the value error.
**Result**
error : valueerror_type
Create a value error when given the description `desc`.
"""
return
[docs]
def memoryerror_create():
"""
fortran-function - Constructor for MemoryError instance.
**Arguments**
desc : character(:), in
Description by the user to describe the memory error.
**Result**
error : memoryerror_type
Create a memory error when given the description `desc`.
"""
return
[docs]
def arithmeticerror_create():
"""
fortran-function - Constructor for ArithmeticError instance.
**Arguments**
desc : character(:), in
Description by the user to describe the arithmetic error.
**Result**
error : arithmeticerror_type
Create a arithmetic error when given the description `desc`.
"""
return
[docs]
def ioerror_from_unit_name():
"""
fortran-function - Constructor for an IOError.
**Arguments**
desc : character(:), in
Text description of the error.
status_value : integer, optional, in
Status value of the io-call.
unit_number : integer, optional, in
Unit of the filehandle.
**Result**
error : IOError_type
Initialized error.
"""
return
[docs]
def ioerror_from_unit_number():
"""
fortran-function - Create and infer unit name from number, unit must be opened
and named.
**Arguments**
desc : character(:), in
Text description of the error.
status_value : integer, optional, in
Status value of the io-call.
unit_number : integer, in
Unit of the filehandle.
**Result**
error : IOError_type
Initialized error.
**Details**
Use only if a file/unit-name is not
accessible otherwise.
"""
return